<template>
    <div class="dynamic-form">
        <el-form ref="formRef" :model="formData" :rules="formRules" :label-width="labelWidth"
            :label-position="labelPosition" :inline="inline" :size="size" :disabled="disabled"
            :validate-on-rule-change="validateOnRuleChange" :hide-required-asterisk="hideRequiredAsterisk"
            :show-message="showMessage" :inline-message="inlineMessage" :status-icon="statusIcon"
            @validate="handleValidate">
            <!-- 动态渲染表单项 -->
            <template v-for="(item, index) in formConfig" :key="item.prop || index">
                <!-- 分组标题 -->
                <div v-if="item.type === 'group'" class="form-group">
                    <div class="group-title">{{ item.label }}</div>
                    <el-row v-if="item.children" :gutter="gutter">
                        <el-col v-for="child in item.children" :key="child.prop" :span="child.span || defaultSpan"
                            :xs="child.xs" :sm="child.sm" :md="child.md" :lg="child.lg" :xl="child.xl">
                            <FormItem :item="child" :form-data="formData" />
                        </el-col>
                    </el-row>
                </div>

                <!-- 普通表单项 -->
                <el-row v-else :gutter="gutter">
                    <el-col :span="item.span || defaultSpan" :xs="item.xs" :sm="item.sm" :md="item.md" :lg="item.lg"
                        :xl="item.xl">
                        <FormItem :item="item" :form-data="formData" />
                    </el-col>
                </el-row>
            </template>

            <!-- 表单操作按钮 -->
            <el-form-item v-if="showButtons" class="form-buttons">
                <el-button v-if="showSubmitButton" type="primary" :loading="submitLoading" @click="handleSubmit">
                    {{ submitButtonText }}
                </el-button>
                <el-button v-if="showResetButton" @click="handleReset">
                    {{ resetButtonText }}
                </el-button>
                <el-button v-if="showCancelButton" @click="handleCancel">
                    {{ cancelButtonText }}
                </el-button>
            </el-form-item>
        </el-form>
    </div>
</template>

<script setup lang="ts">
/**
 * 动态表单组件
 * @author Wu.Liang
 * @description 基于JSON配置的动态表单，支持多种表单控件和验证规则
 */
import { ref, reactive, computed, watch, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import FormItem from './FormItem.vue'
import { showSuccess, showError, showWarning, showInfo } from '@/utils/message'

export interface FormItemConfig {
    // 表单项类型
    type: 'input' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'switch' |
    'date' | 'datetime' | 'time' | 'number' | 'upload' | 'cascader' |
    'color' | 'rate' | 'slider' | 'transfer' | 'group'
    // 字段属性名
    prop?: string
    // 标签文本
    label?: string
    // 占位符
    placeholder?: string
    // 默认值
    defaultValue?: any
    // 是否必填
    required?: boolean
    // 验证规则
    rules?: any[]
    // 是否禁用
    disabled?: boolean
    // 是否只读
    readonly?: boolean
    // 显示条件
    show?: (formData: Record<string, any>) => boolean
    // 禁用条件
    disabledCondition?: (formData: Record<string, any>) => boolean
    // 选项数据（select, radio, checkbox等）
    options?: Array<{ label: string; value: any; disabled?: boolean }>
    // 选项数据源配置
    optionsConfig?: {
        url?: string
        method?: 'GET' | 'POST'
        params?: Record<string, any>
        labelKey?: string
        valueKey?: string
    }
    // 控件特定属性
    props?: Record<string, any>
    // 子项（group类型）
    children?: FormItemConfig[]
    // 栅格布局
    span?: number
    xs?: number
    sm?: number
    md?: number
    lg?: number
    xl?: number
    // 自定义渲染插槽
    slot?: string
}

interface Props {
    // 表单配置
    config: FormItemConfig[]
    // 表单数据
    modelValue?: Record<string, any>
    // 标签宽度
    labelWidth?: string | number
    // 标签位置
    labelPosition?: 'left' | 'right' | 'top'
    // 是否行内表单
    inline?: boolean
    // 表单尺寸
    size?: 'large' | 'default' | 'small'
    // 是否禁用
    disabled?: boolean
    // 栅格间距
    gutter?: number
    // 默认栅格跨度
    defaultSpan?: number
    // 验证配置
    validateOnRuleChange?: boolean
    hideRequiredAsterisk?: boolean
    showMessage?: boolean
    inlineMessage?: boolean
    statusIcon?: boolean
    // 按钮配置
    showButtons?: boolean
    showSubmitButton?: boolean
    showResetButton?: boolean
    showCancelButton?: boolean
    submitButtonText?: string
    resetButtonText?: string
    cancelButtonText?: string
    submitLoading?: boolean
}

const props = withDefaults(defineProps<Props>(), {
    labelWidth: '100px',
    labelPosition: 'right',
    inline: false,
    size: 'default',
    disabled: false,
    gutter: 20,
    defaultSpan: 24,
    validateOnRuleChange: true,
    hideRequiredAsterisk: false,
    showMessage: true,
    inlineMessage: false,
    statusIcon: false,
    showButtons: true,
    showSubmitButton: true,
    showResetButton: true,
    showCancelButton: false,
    submitButtonText: '提交',
    resetButtonText: '重置',
    cancelButtonText: '取消',
    submitLoading: false
})

const emit = defineEmits<{
    'update:modelValue': [data: Record<string, any>]
    'submit': [data: Record<string, any>]
    'reset': []
    'cancel': []
    'validate': [prop: string, isValid: boolean, message: string]
}>()

const formRef = ref<FormInstance>()
const formData = reactive<Record<string, any>>({})

// 计算属性
const formConfig = computed(() => {
    return props.config.filter(item => {
        if (item.show) {
            return item.show(formData)
        }
        return true
    })
})

const formRules = computed(() => {
    const rules: FormRules = {}

    const buildRules = (items: FormItemConfig[]) => {
        items.forEach(item => {
            if (item.prop) {
                const itemRules: any[] = []

                // 必填验证
                if (item.required) {
                    itemRules.push({
                        required: true,
                        message: `请输入${item.label}`,
                        trigger: getValidateTrigger(item.type)
                    })
                }

                // 自定义验证规则
                if (item.rules) {
                    itemRules.push(...item.rules)
                }

                if (itemRules.length > 0) {
                    rules[item.prop] = itemRules
                }
            }

            // 处理分组子项
            if (item.children) {
                buildRules(item.children)
            }
        })
    }

    buildRules(props.config)
    return rules
})

// 获取验证触发时机
const getValidateTrigger = (type: string): string | string[] => {
    const triggers: Record<string, string | string[]> = {
        'input': 'blur',
        'textarea': 'blur',
        'number': 'blur',
        'select': 'change',
        'radio': 'change',
        'checkbox': 'change',
        'switch': 'change',
        'date': 'change',
        'datetime': 'change',
        'time': 'change',
        'cascader': 'change'
    }
    return triggers[type] || 'blur'
}

// 初始化表单数据
const initFormData = () => {
    const data: Record<string, any> = {}

    const initFromConfig = (items: FormItemConfig[]) => {
        items.forEach(item => {
            if (item.prop && item.defaultValue !== undefined) {
                data[item.prop] = item.defaultValue
            }

            if (item.children) {
                initFromConfig(item.children)
            }
        })
    }

    initFromConfig(props.config)

    // 合并传入的数据
    if (props.modelValue) {
        Object.assign(data, props.modelValue)
    }

    Object.assign(formData, data)
}

// 监听配置变化
watch(() => props.config, () => {
    initFormData()
}, { immediate: true, deep: true })

// 监听外部数据变化
watch(() => props.modelValue, (newValue) => {
    if (newValue) {
        Object.assign(formData, newValue)
    }
}, { deep: true })

// 监听表单数据变化
watch(formData, (newValue) => {
    emit('update:modelValue', { ...newValue })
}, { deep: true })

// 事件处理
const handleSubmit = async() => {
    if (!formRef.value) return

    try {
        await formRef.value.validate()
        emit('submit', { ...formData })
    } catch (error) {
        showWarning('请检查表单填写是否正确')
    }
}

const handleReset = () => {
    formRef.value?.resetFields()
    initFormData()
    emit('reset')
}

const handleCancel = () => {
    emit('cancel')
}

const handleValidate = (prop: string, isValid: boolean, message: string) => {
    emit('validate', prop, isValid, message)
}

// 暴露方法
const validate = (callback?: (isValid: boolean) => void) => {
    return formRef.value?.validate(callback)
}

const validateField = (props: string | string[], callback?: (isValid: boolean) => void) => {
    return formRef.value?.validateField(props, callback)
}

const resetFields = (props?: string | string[]) => {
    formRef.value?.resetFields(props)
}

const scrollToField = (prop: string) => {
    formRef.value?.scrollToField(prop)
}

const clearValidate = (props?: string | string[]) => {
    formRef.value?.clearValidate(props)
}

defineExpose({
    validate,
    validateField,
    resetFields,
    scrollToField,
    clearValidate,
    formData
})
</script>

<style lang="scss" scoped>
.dynamic-form {
    .form-group {
        margin-bottom: 20px;

        .group-title {
            font-size: 16px;
            font-weight: 600;
            color: var(--el-text-color-primary);
            margin-bottom: 16px;
            padding-bottom: 8px;
            border-bottom: 1px solid var(--el-border-color-light);
        }
    }

    .form-buttons {
        margin-top: 20px;
        text-align: center;

        :deep(.el-form-item__content) {
            justify-content: center;
        }
    }
}
</style>
